package client;

/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 * ActinoClient.java
 *
 * Steven Louie Apr. 8, 2012
 */
import client.controllers.ServiceManager;
import client.models.ActinoPlayer;
import client.net.*;
import client.ui.StateManager;
import client.ui.states.GameState;
import client.ui.states.LoginState;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.controls.Label;
import de.lessvoid.nifty.slick2d.NiftyBasicGameState;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;

public class ActinoClient extends StateBasedGame {

    public static final int TILE_WIDTH = 16;
    public static final int SCALE_FACTOR = 2;
    private ServiceManager sm;
    private Client client;
    private TcpPacketHandler tcp;
    private boolean connected;
    private ActinoPlayer player;
    private ArrayList<ActinoPlayer> otherPlayers;
    private static ActinoClient instance;

    private ActinoClient() {
        super("ActinoStory");
        otherPlayers = new ArrayList<>();
        sm = ServiceManager.getInstance();
    }

    public static ActinoClient getInstance() {
        if (instance == null) {
            instance = new ActinoClient();
        }
        return instance;
    }

    @Override
    public void initStatesList(GameContainer gc) throws SlickException {
        StateManager.init(this);
        addState(new LoginState());
        addState(new GameState());
        enterState(StateManager.LOGIN);
    }

    public static void main(String[] args) {
        Logger.getLogger("").setLevel(Level.WARNING);
        ActinoClient.getInstance().connect();
        try {
            AppGameContainer app = new AppGameContainer(ActinoClient.getInstance());
            app.setAlwaysRender(true);
            app.setDisplayMode(800, 600, false);
            app.setUpdateOnlyWhenVisible(false);
            app.setVSync(true);
            app.setTargetFrameRate(60);
            app.start();
        } catch (SlickException ex) {
            Logger.getLogger(ActinoClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean connect() {
        client = new Client();
        client.start();
        tcp = new TcpPacketHandler(client);
        sm.startServices();
        
        try {
            client.connect(5000, Network.ADDRESS, Network.PORT);
        } catch (IOException ex) {
            Logger.getLogger(ActinoClient.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (!client.isConnected()) {
            return false;
        }

        Network.register(client);

        client.addListener(new Listener() {

            @Override
            public void connected(Connection connection) {
            }

            @Override
            public void received(Connection connection, Object object) { 

                if (object instanceof ChatMessage) {
                    ChatMessage message = (ChatMessage) object;
                    if (getCurrentStateID() == StateManager.GAME) {
                        System.out.print("CHAT: ");
                        ((GameState) getCurrentState()).displayMessage(message);
                        System.out.print("type: " + message.type);
                        System.out.print("; source: " + message.source);
                        System.out.println("; text: " + message.text);
                    }
                    return;
                }

                if (object instanceof MovementAction) {
                    MovementAction mvt = (MovementAction) object;
                    sm.getMovementService().addMovement(mvt);
                }
                
                if (object instanceof NPCInteraction) {
                    NPCInteraction npcinteract = (NPCInteraction) object;
                    if (getCurrentState() instanceof GameState) {
                        ((GameState) getCurrentState()).createNextWindow(npcinteract.text);
                    }
                }
                
                if (object instanceof LoginAction) {
                    LoginAction login = (LoginAction) object;
                    if (getCurrentStateID() == StateManager.LOGIN) {
                        Nifty nifty = ((NiftyBasicGameState) getCurrentState()).getNifty();
                        String loginstatus = "";
                        switch (login.state) {
                            case 1:
                                player = new ActinoPlayer(login.username, "pikachu", 10, 15);
                                player.initPCor(SCALE_FACTOR * TILE_WIDTH);
                                enterState(StateManager.GAME);
                                break;
                            case 2:
                                loginstatus = "Incorrect information";
                                break;
                            case 3:
                                loginstatus = "Account already logged in";
                                break;
                            case 4:
                                loginstatus = "Too many attempts";
                                break;
                            case 5:
                                loginstatus = "Unknown error";
                                break;
                            default:
                                break;
                        }
                        System.out.println(loginstatus);
                        nifty.getCurrentScreen().findNiftyControl("info", Label.class).
                                setText(loginstatus);
                    }
                }
            }

            @Override
            public void disconnected(Connection connection) {
            }
        });

        return true;
    }

    public Client getKryoClient() {
        return client;
    }
    
    public ActinoPlayer getPlayer() {
        return player;
    }

    public ArrayList<ActinoPlayer> getOtherPlayers() {
        return otherPlayers;
    }

    public TcpPacketHandler getTcp() {
        return tcp;
    }
}
